package lv.solcraft.replication.client.http;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import lv.solcraft.replication.common.OperDTO;
import lv.solcraft.replication.common.OperStateDTO;
import lv.solcraft.replication.common.server.ExecutingFacade;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.restlet.Client;
import org.restlet.data.CharacterSet;
import org.restlet.data.Encoding;
import org.restlet.data.Language;
import org.restlet.data.MediaType;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.StringRepresentation;
import org.springframework.util.Assert;

import com.noelios.restlet.application.DecodeRepresentation;
import com.noelios.restlet.application.EncodeRepresentation;

public class HttpExecutingFacade implements ExecutingFacade {

    private String serverUrl;

    public void setServerUrl(String serverUrl) {
        this.serverUrl = serverUrl;
    }

    public List<OperDTO> loadOpers(String serverName, int forSiteId) {
        JSONArray jsonArray;
        try {
            jsonArray = loadOpersRequest(serverName, forSiteId);
        } catch (IOException e) {
            throw new RuntimeException("IO error while making HTTP GET request to load opers", e);
        }
        List<OperDTO> opers = new ArrayList<OperDTO>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject json = jsonArray.getJSONObject(i);
            OperDTO oper = OperConverter.convert(json);
            opers.add(oper);
        }
        return opers;
    }

    public void updateOperStates(String serverName, List<OperStateDTO> states, int forSiteId) {
        JSONArray statesJson = new JSONArray();
        for (OperStateDTO state : states) {
            JSONObject json = OperConverter.convert(state);
            statesJson.add(json);
        }
        try {
            updateStatesRequest(serverName, forSiteId, statesJson);
        } catch (IOException e) {
            throw new RuntimeException("IO error while making oper state update HTTP POST request", e);
        }
    }

    private void updateStatesRequest(String server, int siteId, JSONArray statesJson) throws IOException {
        Representation representation = new EncodeRepresentation(Encoding.GZIP, new StringRepresentation(statesJson
                .toString(), MediaType.TEXT_PLAIN, Language.ALL, CharacterSet.UTF_8));
        String urlString = getUrl(server, siteId);
        Client client = HttpClientFactory.get();
        Response response = client.post(urlString, representation);
        try {
            String responseText = response.isEntityAvailable() ? new DecodeRepresentation(response.getEntity())
                    .getText() : null;
            Assert.isTrue(response.getStatus().isSuccess(), "Update opers state request failed with response code: "
                    + response.getStatus().getCode() + ", url" + urlString + ", response " + responseText);
        } finally {
            response.release();
        }
    }

    private String getUrl(String server, int siteId) {
        return serverUrl + "/" + server + "/execute/" + siteId;
    }

    private JSONArray loadOpersRequest(String server, int siteId) throws IOException {
        String urlString = getUrl(server, siteId);
        Client client = HttpClientFactory.get();
        Response response = client.get(urlString);
        try {
            String responseText = response.isEntityAvailable() ? new DecodeRepresentation(response.getEntity())
                    .getText() : null;
            Assert.isTrue(response.getStatus().isSuccess(), "Loading opers request failed with response code: "
                    + response.getStatus().getCode() + ", url" + urlString + ", response " + responseText);
            JSONArray json = JSONArray.fromObject(responseText);
            return json;
        } finally {
            response.release();
        }
    }
}
